#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <event.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include "colorido.h"
#include "net.h"
#include "squid.h"
#include "mod.h"
#include "list.h"

//707d0eeb18366e725ff8d9d3d25a2db7
//allkindsofbdsm.com/
//

int running;



void free_coner(coner *c){
	printf("closing con\n");
	event_del(&c->ev);
	free(c);
}

coner *alloc_coner(){
	coner *ncon;
	ncon = malloc(sizeof(coner));
	memset(ncon,0,sizeof(coner));
	return ncon;
}


qsend *qpop(ctrler *base){
	qsend *q=NULL;
	pthread_mutex_lock(&base->mutex);
	if(base->que->count == 0){
		pthread_cond_wait(&base->cond,&base->mutex);
	}
	q = queue_dequeue(base->que);
	pthread_mutex_unlock(&base->mutex);
	return q;
}




void *run_modules(list *pqueue,squid_t *req)
{
  list_node *i=pqueue->head;
  colorido_mod_t *mod;
  while(i)
  {
    list_node *pnext=i->next;
	mod = i->item;

	printf("runing %s\n",mod->name);
    if(mod->process(req)==0)return mod;
      i=pnext;
  }
    return 0;
}




void send_resp(qsend *q,squid_t *sq){
	char resp[NET_WRITE_SIZE];
	int retsize;

	if(sq->resp == NULL)
		retsize = snprintf(resp,NET_WRITE_SIZE,"%s\n",sq->requestid);
	else{
		retsize = snprintf(resp,NET_WRITE_SIZE,"%s %s\n",sq->requestid,sq->resp);
		free(sq->resp);
	}
	send(q->con->sock,resp,retsize,0);
}



void work(qsend *q){
	squid_t sq;
	colorido_mod_t *mod;

	if(squid_parse(&sq,q->req)==FALSE){
		printf("squid p error\n");
		//disconnect the client to prevent future errors
		close(q->con->sock);
		free_coner(q->con);
		return;
	}

	if((mod=run_modules(q->con->base->modules,&sq))!=NULL){
		printf("mod %s answered\n",mod->name);
	}
		send_resp(q,&sq);
}

void qsend_free(qsend *q){
	free(q->req);
	free(q);
}

void *tr_monitor(void *arg){
	ctrler *base = (ctrler *)arg;
	qsend *q;

	while(running==TRUE){
		q = qpop(base);
		if(q==NULL)continue;
		work(q);
		qsend_free(q);
	}
	return NULL;
}


int main(int argc,char **argv){
	ctrler base;
	pthread_t tid;
	int i;
	colorido_mod_t *mod;
	void (*inim)(colorido_mod_t *);



	event_init();

	pthread_mutex_init(&base.mutex,NULL);
	pthread_cond_init(&base.cond,NULL);
	base.que = list_new();
	base.modules = list_new();
	//load modules
	mod = malloc(sizeof(colorido_mod_t));
	memset(mod,0,sizeof(colorido_mod_t));
	mod->dl = dlopen(COLOR_PREFIX"/lib/google.so",RTLD_LAZY);
	inim = dlsym(mod->dl,"colorido_init");
	inim(mod);
	if(mod->init && mod->init() == 0){
		printf("module %s loaded\n",mod->name);
		queue_enqueue(base.modules,mod);
	}else{
		printf("module %s failed\n",mod->name);
		free(mod);
	}

	
	  
	running = TRUE;

	net_init(&base);

	for(i=0;i<10;i++)
		pthread_create(&tid,NULL,tr_monitor,&base);


	event_dispatch();
	return 0;
}
